#include "Huevo.h"
#include "ActoresConstantes.h"
#include "UtilidadesConstantes.h"

using namespace TP::Juego::Arena::Actores;

Huevo::Huevo() : Actor("", new Rol(HUEVO, DESC_ACTOR)) {
	setEsEnemigo(false);
	_jugadorMiembro = NULL;
}

Huevo::Huevo(const string& pNombre) : Actor(pNombre, new Rol(pNombre,
DESC_ACTOR)) {
	setEsEnemigo(false);
	_jugadorMiembro = NULL;
}

Huevo::~Huevo() {}

IColisionado* Huevo::colisionar(IColisionado* pColisionado) {
    if (pColisionado->getRol()->Nombre() == ROL_CERDITO) return pColisionado;
    
	// Si colisiono contra el piso.
	if (pColisionado->getRol()->Descripcion() == DESC_PISO) {
		return (IColisionado*)colisionarContraPiso((Piso*)pColisionado);
	} // Si colisiono contra el perímetro.
	else if (pColisionado->getRol()->Descripcion() == DESC_PERIMETRO) {
		return (IColisionado*)colisionarContraPerimetro(
				(Perimetro*)pColisionado);
	} // Si colisiono contra una utilidad.
	else if (pColisionado->getRol()->Descripcion() == DESC_UTILIDAD) {
		return (IColisionado*)colisionarContraUtilidad((Utilidad*)pColisionado);
	} // Si colisiono contra un actor.
	else if (pColisionado->getRol()->Descripcion() == DESC_ACTOR) {
		return (IColisionado*)colisionarContraActor((Actor*)pColisionado);
	}
}

Actor* Huevo::colisionarContraActor(Actor* pActor) {
	long int dx = pow(this->getTrayectoria()->getPosicion()->X() -
			pActor->getTrayectoria()->getPosicion()->X(), 2);
	long int dy = pow(this->getTrayectoria()->getPosicion()->Y() -
			pActor->getTrayectoria()->getPosicion()->Y(), 2);
	long int dr = sqrt(dx + dy);
	long int sumRadio = this->getRadio() + pActor->getRadio();

	if ((dr < sumRadio) && (this->esEnemigo() != pActor->esEnemigo())) {
		this->destruir();
//		if (pActor->destruido())
//			_jugadorMiembro->incrementarPuntaje(pActor->getPuntosDestruccion());
	}
	return pActor;
}

Utilidad* Huevo::colisionarContraUtilidad(Utilidad* pUtilidad) {
	long int dx = pow(this->getTrayectoria()->getPosicion()->X() -
		pUtilidad->getPosicion()->X(), 2);
	long int dy = pow(this->getTrayectoria()->getPosicion()->Y() -
		pUtilidad->getPosicion()->Y(), 2);
	long int dr = sqrt(dx + dy);
	long int sumRadio = this->getRadio() + pUtilidad->getRadio();

	// Si la distancia entre los centros es < a la suma de los radios -> choque
	if ((dr < sumRadio)) {
		pUtilidad->decrementarEnergia(this->getDanioContraSuperficie());
//		if (pUtilidad->destruido())
//			this->_jugadorMiembro->incrementarPuntaje(
//					pUtilidad->getPuntosDestruccion());
		this->destruir();
	}
	return pUtilidad;
}

Perimetro* Huevo::colisionarContraPerimetro(Perimetro* pPerimetro) {
	if ((getTrayectoria()->getPosicion()->X() - getRadio() < 0) ||
			(getTrayectoria()->getPosicion()->X() + getRadio() >
			pPerimetro->getAncho()) || (getTrayectoria()->getPosicion()->Y() -
			getRadio() < 0) || (getTrayectoria()->getPosicion()->Y() + getRadio(
			) > pPerimetro->getAlto()))
		this->destruir();
	return pPerimetro;
}

Piso* Huevo::colisionarContraPiso(Piso* pPiso) {
	vector<Posicion*> posiciones = pPiso->getVectorPosiciones();
	double pendiente, puntoDePaso, distancia_punto_recta;
	double xPajaro = this->getTrayectoria()->getPosicion()->X();
	double yPajaro = this->getTrayectoria()->getPosicion()->Y();

	if (!posiciones.empty()) {
		// Si hay puntos de piso -> recorro todos esos puntos.
		for (size_t i = 0; i < posiciones.size() - 1; ++i) {
			// Saco la pendiente y el punto de paso que une 2 puntos contiguos.
			this->_obtenerAtributosDeRecta(posiciones[i], posiciones[i + 1],
					pendiente, puntoDePaso);
			// Saco la distancia del centro del pájaro a la recta.
			distancia_punto_recta = abs(pendiente * xPajaro - yPajaro +
					puntoDePaso) / sqrt(pow(pendiente, 2) + 1);
			// Me fijo si esa distancia es menor que el radio.
			if (this->getRadio() > distancia_punto_recta) {
				//hago el rebote
				this->destruir(); // Mato el huevo.
			}
		}
	}
	return pPiso;
}

string Huevo::aXML() {
	TiXmlDocument* doc = new TiXmlDocument();
	TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", "");
	doc->LinkEndChild(decl);

	doc->LinkEndChild(this->aElementoXML());

	TiXmlPrinter printer;
	doc->Accept(&printer);
	return printer.CStr();
}

string Huevo::aXML(const string& pPath) {
	TiXmlDocument* doc = new TiXmlDocument(pPath.c_str());
	TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", "");
	doc->LinkEndChild(decl);

	doc->LinkEndChild(this->aElementoXML());

	TiXmlPrinter printer;
	doc->Accept(&printer);
	return printer.CStr();
}

void Huevo::parseXML(const string& pDescriptor) {
	TiXmlDocument doc;
	doc.Parse(pDescriptor.c_str(), 0, TIXML_ENCODING_UTF8);
	this->deElementoXML(doc.FirstChildElement());
}

Jugador* Huevo::getJugadorMiembro() const {
	return _jugadorMiembro;
}

void Huevo::setJugadorMiembro(Jugador* jugadorMiembro) {
	_jugadorMiembro = jugadorMiembro;
}